{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "import numpy as np\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.ensemble import IsolationForest\n",
    "from DrissionPage import SessionPage"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 从提供公开信息的网站上下载相关信息，根据需要什么指标数据，定义文件名列表，然后去open_digger爬取，然后存入.json文件，文件名可自定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO 批量得到网站上展示的一些项目信息，以后再彻底实现\n",
    "s = SessionPage()\n",
    "s.get('https://www.qucheng.cc/project-browse--53-100-1.html')\n",
    "eles = s.eles('t:a@@class=project-box')\n",
    "urlList = []\n",
    "for e in eles:\n",
    "    s.get(e.attr('href'))\n",
    "    ats = s.eles('.text-ellipsis')[1:]\n",
    "    for at in ats:\n",
    "        print(at.text.split('/'))\n",
    "        urlList.append(at.text.split('/'))\n",
    "\n",
    "save_path = 'urlList.json'\n",
    "with open(save_path,'w') as f:\n",
    "    f.write(json.dumps(urlList,indent=4))\n",
    "    f.close()\n",
    "\n",
    "repos = [\n",
    "    '{}/{}/{}'.format(u[2].split('.')[0],u[3],u[4]) for u in urlList\n",
    "]\n",
    "\n",
    "file_names = [\n",
    "    'issue_comments.json',\n",
    "    'issues_new.json',\n",
    "    'change_requests.json',\n",
    "    'change_requests_reviews.json',\n",
    "    'change_requests_accepted.json'\n",
    "]\n",
    "\n",
    "# rst存结果\n",
    "rst = {}\n",
    "s = SessionPage()\n",
    "for i in repos:\n",
    "    tp = {}\n",
    "    for j in file_names:\n",
    "        s.get('https://oss.x-lab.info/open_digger/'+i+'/'+j)\n",
    "        tp[j] = s.response.text\n",
    "    rst[i] = tp\n",
    "with open(save_path,'w') as f:\n",
    "    f.write(json.dumps(rst,indent=4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 对下载的信息进行处理，提取所需的必要数据，并处理异常值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "指标： {'change_requests_reviews', 'change_requests', 'change_requests_accepted', 'issue_comments', 'issues_new'}\n",
      "原数据集： [[0, 0, 0, 44, 22], [0, 1, 0, 2, 2], [444, 262, 231, 326, 171], [10, 18, 12, 407, 0], [0, 0, 0, 4, 0], [0, 1, 0, 4, 1], [1, 2, 2, 6, 1], [92, 82, 78, 85, 43], [16, 365, 330, 92, 36], [14, 57, 57, 301, 29], [0, 0, 0, 5, 2], [0, 1, 0, 1, 0], [89, 48, 43, 148, 87], [750, 543, 432, 1170, 171], [32, 36, 19, 123, 22], [63, 120, 100, 410, 73], [0, 2, 0, 105, 26], [0, 3, 2, 13, 5], [20, 11, 6, 16, 12], [0, 0, 0, 20, 1], [0, 0, 0, 1, 0], [0, 2, 2, 60, 20], [0, 1, 0, 1, 0], [0, 0, 0, 12, 9], [0, 2, 2, 6, 2], [0, 19, 21, 39, 30], [0, 35, 34, 11, 6], [0, 4, 4, 21, 1], [0, 0, 0, 30, 4], [0, 3, 3, 15, 3], [0, 1, 3, 3, 2], [0, 3, 0, 12, 4], [0, 0, 0, 14, 7], [0, 0, 0, 1, 0], [0, 0, 1, 131, 41], [2, 7, 6, 148, 2], [0, 0, 0, 33, 26], [0, 1, 0, 29, 21], [2, 3, 0, 3, 0], [0, 0, 0, 4, 2], [1, 11, 10, 0, 0], [7, 8, 6, 25, 13], [1, 22, 11, 156, 68], [28, 83, 78, 402, 17], [51, 58, 53, 34, 7]] \n",
      " 正常值： [array([ 0,  0,  0, 44, 22]), array([0, 1, 0, 2, 2]), array([0, 0, 0, 4, 0]), array([0, 1, 0, 4, 1]), array([1, 2, 2, 6, 1]), array([0, 0, 0, 5, 2]), array([0, 1, 0, 1, 0]), array([ 32,  36,  19, 123,  22]), array([  0,   2,   0, 105,  26]), array([ 0,  3,  2, 13,  5]), array([20, 11,  6, 16, 12]), array([ 0,  0,  0, 20,  1]), array([0, 0, 0, 1, 0]), array([ 0,  2,  2, 60, 20]), array([0, 1, 0, 1, 0]), array([ 0,  0,  0, 12,  9]), array([0, 2, 2, 6, 2]), array([ 0, 19, 21, 39, 30]), array([ 0, 35, 34, 11,  6]), array([ 0,  4,  4, 21,  1]), array([ 0,  0,  0, 30,  4]), array([ 0,  3,  3, 15,  3]), array([0, 1, 3, 3, 2]), array([ 0,  3,  0, 12,  4]), array([ 0,  0,  0, 14,  7]), array([0, 0, 0, 1, 0]), array([  0,   0,   1, 131,  41]), array([  2,   7,   6, 148,   2]), array([ 0,  0,  0, 33, 26]), array([ 0,  1,  0, 29, 21]), array([2, 3, 0, 3, 0]), array([0, 0, 0, 4, 2]), array([ 1, 11, 10,  0,  0]), array([ 7,  8,  6, 25, 13])] \n",
      "异常值： [[ 444  262  231  326  171]\n",
      " [  10   18   12  407    0]\n",
      " [  92   82   78   85   43]\n",
      " [  16  365  330   92   36]\n",
      " [  14   57   57  301   29]\n",
      " [  89   48   43  148   87]\n",
      " [ 750  543  432 1170  171]\n",
      " [  63  120  100  410   73]\n",
      " [   1   22   11  156   68]\n",
      " [  28   83   78  402   17]\n",
      " [  51   58   53   34    7]]\n"
     ]
    }
   ],
   "source": [
    "def deal_json(filename='od-res.json',year='2023'):\n",
    "    datalist = []\n",
    "    repos = []\n",
    "    metrics = set()\n",
    "    with open(filename,'r',encoding='utf-8') as f:\n",
    "        data = json.loads(f.read())\n",
    "    # 记录所有repo和metric\n",
    "    for k,v in data.items():\n",
    "        repos.append(k)\n",
    "        metrics.update({i.split('.')[0] for i in v})\n",
    "    print('指标：',metrics)\n",
    "    # 记录指定年份的指标数据，并整理成适合矩阵的列表 \n",
    "    for repo in repos:\n",
    "        # print('repo:',repo)\n",
    "        row = []\n",
    "        for metric in metrics: \n",
    "            try:\n",
    "                row.append(json.loads(data[repo][metric+'.json'])[year])\n",
    "            except json.JSONDecodeError or KeyError:\n",
    "                row.append(0)\n",
    "            except KeyError:\n",
    "                row.append(0)\n",
    "        if sum(row) == 0: continue\n",
    "        datalist.append(row)\n",
    "\n",
    "    return datalist\n",
    "\n",
    "# 使用孤立森林处理异常值\n",
    "def outlier_detection(data):\n",
    "    # 异常值检测\n",
    "    clf = IsolationForest(contamination='auto',random_state=42)  # 随机森林\n",
    "    # 拟合模型\n",
    "    clf.fit(data)\n",
    "    # 预测数据集的异常值分数\n",
    "    scores = clf.decision_function(data)\n",
    "    y_pred = clf.predict(data)\n",
    "    # 异常值标记\n",
    "    outlier_index = np.where(y_pred == -1)\n",
    "    # 异常值处理\n",
    "    data_clean = np.delete(data, outlier_index[0], axis=0)\n",
    "    # 异常值收集\n",
    "    outliers = data[outlier_index]\n",
    "    return data_clean,outliers\n",
    "\n",
    "\n",
    "datalist = deal_json()\n",
    "# 异常值处理\n",
    "data_clean,outliers = outlier_detection(np.array(datalist))\n",
    "print('原数据集：',datalist,'\\n','正常值：',list(data_clean),'\\n异常值：',outliers)\n",
    "# print('\\n异常值：',outliers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3. 进行主成分分析方法定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "def pca(X_scaled:list):\n",
    "\n",
    "    # 创建PCA对象，可以指定你想要的主成分的数量\n",
    "    pca = PCA()\n",
    "    \n",
    "    # fit_transform 会按照pca对象指定的维数，对原始数据进行降维，返回降维的矩阵\n",
    "    X_pca = pca.fit_transform(X_scaled,)\n",
    "\n",
    "    # 之前没有指定维度，所以pca对象的主成分信息与原始数据的维度相同\n",
    "    print(\" 标准化后的形状:\", X_scaled.shape,\" 主成分矩阵的形状:\", X_pca.shape,\" 权重矩阵的形状:\", pca.components_.shape)\n",
    "    \n",
    "    # 获得每个主成分的解释的方差\n",
    "    variances = pca.explained_variance_ratio_\n",
    "\n",
    "    # 打印每个主成分解释的方差比例\n",
    "    print(\"各主成分的方差比例: \", variances)\n",
    "\n",
    "    # 选择超过一定方差比例的主成分\n",
    "    i=0\n",
    "    for r in np.cumsum(variances):\n",
    "        i+=1\n",
    "        if r > 0.9:\n",
    "            # 打印计算累积方差比率\n",
    "            print(\"累积方差比率: \", np.cumsum(variances)[:i],)\n",
    "            print(\"需要 {} 个主成分来解释 90% 的方差\".format(i))\n",
    "            break\n",
    "\n",
    "    # 将X_pca降到i维\n",
    "    # X_pca = X_pca[:,:i]\n",
    "    print(\"降维后数据的形状: \", X_pca.shape)\n",
    "\n",
    "    # 如果需要查看每个主成分的权重（在原始特征空间中的系数），可以打印components_\n",
    "    print(\"主成分的权重（系数）: \\n\", pca.components_,)\n",
    "    return pca.components_,X_pca\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "4. 进行PCA计算（为了获得中间过程量未使用上面定义的方法）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "指标： {'change_requests_reviews', 'change_requests', 'change_requests_accepted', 'issue_comments', 'issues_new'}\n",
      "X标准化: [[-0.28450787 -0.56679718 -0.5396961  -0.37414505 -0.71165099]\n",
      " [-0.28450787 -0.51291912 -0.48178879  0.79505823  1.96218222]\n",
      " [-0.03493956  0.45688594  0.50263542  0.10219703  0.21390666]\n",
      " [-0.28450787 -0.08189465 -0.01853034 -0.37414505 -0.1974523 ]\n",
      " [-0.22211579 -0.29740689 -0.30806687 -0.72057565 -0.60881125]\n",
      " [ 1.33768613  1.80383742  1.02380118  0.66514675 -0.71165099]\n",
      " [-0.28450787  3.52793531  3.68753728  3.30668009  2.27070144]\n",
      " [-0.15972372 -0.29740689 -0.48178879  1.31470413  0.00822718]\n",
      " [ 4.64446622 -0.08189465 -0.07643764 -0.20092975  0.21390666]\n",
      " [-0.28450787 -0.45904106 -0.42388148  0.53523528 -0.50597152]\n",
      " [-0.28450787 -0.405163   -0.36597418 -0.76387948 -0.71165099]\n",
      " [-0.28450787 -0.405163   -0.42388148 -0.76387948 -0.1974523 ]\n",
      " [-0.28450787 -0.51291912 -0.42388148 -0.72057565 -0.71165099]\n",
      " [-0.28450787 -0.56679718 -0.5396961  -0.72057565 -0.71165099]\n",
      " [-0.28450787 -0.51291912 -0.48178879 -0.633968   -0.71165099]\n",
      " [-0.28450787 -0.56679718 -0.5396961  -0.67727183 -0.71165099]\n",
      " [-0.28450787 -0.56679718 -0.5396961  -0.50405653 -0.40313178]\n",
      " [-0.28450787 -0.51291912 -0.5396961  -0.24423357 -0.50597152]\n",
      " [-0.28450787 -0.56679718 -0.5396961  -0.33084122 -0.60881125]\n",
      " [-0.28450787 -0.51291912 -0.5396961  -0.72057565 -0.71165099]\n",
      " [-0.28450787 -0.56679718 -0.5396961  -0.72057565 -0.71165099]\n",
      " [-0.28450787  1.64220324  1.83450347 -0.76387948 -0.1974523 ]\n",
      " [-0.15972372 -0.35128495 -0.36597418  0.62184293  1.24230405]\n",
      " [-0.28450787 -0.51291912 -0.48178879  2.13747681  2.68206039]\n",
      " [-0.28450787  1.42669101  1.60287424 -0.24423357  1.03662457]] 标准差: [16.02767606 18.56043103 17.26897797 23.09264818  9.72386754]\n",
      " 标准化后的形状: (25, 5)  主成分矩阵的形状: (25, 5)  权重矩阵的形状: (5, 5)\n",
      "各主成分的方差比例:  [0.5607714  0.21090493 0.1849877  0.04144509 0.00189089]\n",
      "累积方差比率:  [0.5607714  0.77167632 0.95666403]\n",
      "需要 3 个主成分来解释 90% 的方差\n",
      "降维后数据的形状:  (25, 5)\n",
      "主成分的权重（系数）: \n",
      " [[ 0.0487121   0.52580407  0.52778893  0.4917805   0.4480491 ]\n",
      " [ 0.7441655   0.31482315  0.26953252 -0.32583043 -0.41023268]\n",
      " [ 0.66526265 -0.35283847 -0.37800836  0.32758432  0.42746791]\n",
      " [ 0.00429264 -0.04627283  0.16520517 -0.73048551  0.66101329]\n",
      " [-0.03538398  0.70553548 -0.691815   -0.10519458  0.10627217]]\n",
      "X主成分: [[-1.09958069e+00 -1.21777131e-01 -2.12046988e-01 -2.61257788e-01\n",
      "  -5.27293035e-02]\n",
      " [ 7.32311390e-01 -1.56706293e+00  1.27304387e+00  6.59168932e-01\n",
      "   1.06382634e-01]\n",
      " [ 6.49915109e-01  1.32263644e-01 -2.49534939e-01  1.28488276e-01\n",
      "  -1.21634318e-02]\n",
      " [-3.39165187e-01 -3.95885735e-02 -3.60340827e-01  1.42295846e-01\n",
      "  -1.65186449e-02]\n",
      " [-9.56934151e-01  1.42584222e-01 -4.22673457e-01  8.58519017e-02\n",
      "   2.22544770e-02]\n",
      " [ 1.56222909e+00  1.91451479e+00 -2.19872336e-01 -8.64880048e-01\n",
      "   3.71459089e-01]\n",
      " [ 6.43093165e+00 -1.16066942e-01 -7.74115137e-01 -4.69786698e-01\n",
      "  -1.58475523e-01]\n",
      " [ 2.31791018e-01 -7.74094873e-01  6.14991869e-01 -1.02145182e+00\n",
      "  -8.29616472e-03]\n",
      " [ 1.39865553e-01  3.38758427e+00  3.17319635e+00  2.99270015e-01\n",
      "  -1.25369548e-01]\n",
      " [-4.42426398e-01 -4.37317434e-01  9.19737273e-02 -7.75443084e-01\n",
      "  -1.30629704e-01]\n",
      " [-1.11456807e+00  1.02920094e-01 -4.62416968e-01  4.46580526e-02\n",
      "  -1.78761377e-02]\n",
      " [-9.14744642e-01 -1.23628915e-01 -2.20724080e-01  3.74983636e-01\n",
      "   7.68300144e-02]\n",
      " [-1.18049353e+00  3.92783669e-02 -3.88321364e-01  8.44482984e-03\n",
      "  -5.83960863e-02]\n",
      " [-1.26994851e+00 -8.89949809e-03 -3.25532220e-01 -8.19525277e-03\n",
      "  -1.62866820e-02]\n",
      " [-1.16846442e+00 -4.54894364e-03 -3.38060610e-01 -6.43873905e-02\n",
      "  -2.74455985e-02]\n",
      " [-1.24865253e+00 -2.30092022e-02 -3.11346566e-01 -3.98280697e-02\n",
      "  -2.08420097e-02]\n",
      " [-1.02523687e+00 -2.06012682e-01 -1.22721885e-01  3.75759643e-02\n",
      "  -6.27631512e-03]\n",
      " [-9.15208954e-01 -2.31520625e-01 -1.00578901e-01 -2.22692462e-01\n",
      "  -6.52440101e-03]\n",
      " [-1.03220746e+00 -1.78075056e-01 -1.53900646e-01 -2.24912171e-01\n",
      "  -4.63556295e-02]\n",
      " [-1.24161920e+00  8.06256220e-03 -3.44542472e-01 -1.06883431e-02\n",
      "   2.17262001e-02]\n",
      " [-1.26994851e+00 -8.89949809e-03 -3.25532220e-01 -8.19525277e-03\n",
      "  -1.62866820e-02]\n",
      " [ 1.35371944e+00  1.12963757e+00 -1.79680205e+00  6.53343075e-01\n",
      "  -4.10650521e-02]\n",
      " [ 4.76778790e-01 -1.04034452e+00  8.90781026e-01  3.22040717e-01\n",
      "   7.76019312e-02]\n",
      " [ 1.71502744e+00 -2.29978131e+00  2.02052396e+00  1.54400644e-01\n",
      "   4.16704875e-02]\n",
      " [ 1.92662964e+00  3.23782613e-01 -9.35447146e-01  1.06119649e+00\n",
      "   4.36120814e-02]]\n",
      "标准化X乘权重转置: [[-1.09958069e+00 -1.21777131e-01 -2.12046988e-01 -2.61257788e-01\n",
      "  -5.27293035e-02]\n",
      " [ 7.32311390e-01 -1.56706293e+00  1.27304387e+00  6.59168932e-01\n",
      "   1.06382634e-01]\n",
      " [ 6.49915109e-01  1.32263644e-01 -2.49534939e-01  1.28488276e-01\n",
      "  -1.21634318e-02]\n",
      " [-3.39165187e-01 -3.95885735e-02 -3.60340827e-01  1.42295846e-01\n",
      "  -1.65186449e-02]\n",
      " [-9.56934151e-01  1.42584222e-01 -4.22673457e-01  8.58519017e-02\n",
      "   2.22544770e-02]\n",
      " [ 1.56222909e+00  1.91451479e+00 -2.19872336e-01 -8.64880048e-01\n",
      "   3.71459089e-01]\n",
      " [ 6.43093165e+00 -1.16066942e-01 -7.74115137e-01 -4.69786698e-01\n",
      "  -1.58475523e-01]\n",
      " [ 2.31791018e-01 -7.74094873e-01  6.14991869e-01 -1.02145182e+00\n",
      "  -8.29616472e-03]\n",
      " [ 1.39865553e-01  3.38758427e+00  3.17319635e+00  2.99270015e-01\n",
      "  -1.25369548e-01]\n",
      " [-4.42426398e-01 -4.37317434e-01  9.19737273e-02 -7.75443084e-01\n",
      "  -1.30629704e-01]\n",
      " [-1.11456807e+00  1.02920094e-01 -4.62416968e-01  4.46580526e-02\n",
      "  -1.78761377e-02]\n",
      " [-9.14744642e-01 -1.23628915e-01 -2.20724080e-01  3.74983636e-01\n",
      "   7.68300144e-02]\n",
      " [-1.18049353e+00  3.92783669e-02 -3.88321364e-01  8.44482984e-03\n",
      "  -5.83960863e-02]\n",
      " [-1.26994851e+00 -8.89949809e-03 -3.25532220e-01 -8.19525277e-03\n",
      "  -1.62866820e-02]\n",
      " [-1.16846442e+00 -4.54894364e-03 -3.38060610e-01 -6.43873905e-02\n",
      "  -2.74455985e-02]\n",
      " [-1.24865253e+00 -2.30092022e-02 -3.11346566e-01 -3.98280697e-02\n",
      "  -2.08420097e-02]\n",
      " [-1.02523687e+00 -2.06012682e-01 -1.22721885e-01  3.75759643e-02\n",
      "  -6.27631512e-03]\n",
      " [-9.15208954e-01 -2.31520625e-01 -1.00578901e-01 -2.22692462e-01\n",
      "  -6.52440101e-03]\n",
      " [-1.03220746e+00 -1.78075056e-01 -1.53900646e-01 -2.24912171e-01\n",
      "  -4.63556295e-02]\n",
      " [-1.24161920e+00  8.06256220e-03 -3.44542472e-01 -1.06883431e-02\n",
      "   2.17262001e-02]\n",
      " [-1.26994851e+00 -8.89949809e-03 -3.25532220e-01 -8.19525277e-03\n",
      "  -1.62866820e-02]\n",
      " [ 1.35371944e+00  1.12963757e+00 -1.79680205e+00  6.53343075e-01\n",
      "  -4.10650521e-02]\n",
      " [ 4.76778790e-01 -1.04034452e+00  8.90781026e-01  3.22040717e-01\n",
      "   7.76019312e-02]\n",
      " [ 1.71502744e+00 -2.29978131e+00  2.02052396e+00  1.54400644e-01\n",
      "   4.16704875e-02]\n",
      " [ 1.92662964e+00  3.23782613e-01 -9.35447146e-01  1.06119649e+00\n",
      "   4.36120814e-02]]\n"
     ]
    }
   ],
   "source": [
    "datalist = deal_json(year='2022Q3')\n",
    "# 异常值处理\n",
    "data_clean,outliers = outlier_detection(np.array(datalist))\n",
    "X = np.array(data_clean)\n",
    "# 在应用PCA之前，需要对数据进行标准化处理\n",
    "scaler = StandardScaler()\n",
    "X_scaled = scaler.fit_transform(X)\n",
    "print('X标准化:',X_scaled,'标准差:',scaler.scale_)\n",
    "# w,X_pca = pca(X_scaled)\n",
    "# 创建PCA对象，可以指定你想要的主成分的数量\n",
    "pca = PCA()\n",
    "\n",
    "# fit_transform 会按照pca对象指定的维数，对原始数据进行降维，返回降维的矩阵\n",
    "X_pca = pca.fit_transform(X_scaled)\n",
    "\n",
    "# 之前没有指定维度，所以pca对象的主成分信息与原始数据的维度相同\n",
    "print(\" 标准化后的形状:\", X_scaled.shape,\" 主成分矩阵的形状:\", X_pca.shape,\" 权重矩阵的形状:\", pca.components_.shape)\n",
    "\n",
    "# 获得每个主成分的解释的方差\n",
    "variances = pca.explained_variance_ratio_\n",
    "\n",
    "# 打印每个主成分解释的方差比例\n",
    "print(\"各主成分的方差比例: \", variances)\n",
    "\n",
    "# 选择超过一定方差比例的主成分\n",
    "i=0\n",
    "for r in np.cumsum(variances):\n",
    "    i+=1\n",
    "    if r > 0.9:\n",
    "        # 打印计算累积方差比率\n",
    "        print(\"累积方差比率: \", np.cumsum(variances)[:i],)\n",
    "        print(\"需要 {} 个主成分来解释 90% 的方差\".format(i))\n",
    "        break\n",
    "\n",
    "# 将X_pca降到i维\n",
    "X_pca = X_pca[:,:i]\n",
    "print(\"降维后数据的形状: \", X_pca.shape)\n",
    "\n",
    "# 如果需要查看每个主成分的权重（在原始特征空间中的系数），可以打印components_\n",
    "print(\"主成分的权重（系数）: \\n\", pca.components_,)\n",
    "\n",
    "print('X主成分:',X_pca)\n",
    "# 将矩阵转置\n",
    "Y = X_scaled@np.array(pca.components_).T\n",
    "print('标准化X乘权重转置:',Y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获得权重"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0.21317545448228947,\n",
       " 0.17687533380337417,\n",
       " 0.18561569903579928,\n",
       " 0.11414440802894188,\n",
       " 0.31018910464959526]"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "标准差 = scaler.scale_\n",
    "各主成分的方差比例 = variances\n",
    "\n",
    "主成分的权重 = pca.components_\n",
    "w0 = np.dot(各主成分的方差比例, 主成分的权重)\n",
    "w = [w0[i]/标准差[i] for i in range(5)]\n",
    "[ i/sum(w) for i in w]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 记录五指标权重变化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "22Q4[0.3759998776217023,\n",
    " 0.25827668462325704,\n",
    " 0.26134229033785006,\n",
    " -0.009929134539166563,\n",
    " 0.11431028195635716]\n",
    "Q1[0.32512307189797895,\n",
    " 0.17962019199236826,\n",
    " 0.1639920087505356,\n",
    " 0.07524358719002916,\n",
    " 0.2560211401690881]\n",
    "Q2[0.20678901853362505,\n",
    " 0.2555938933030104,\n",
    " 0.2807109628385174,\n",
    " 0.06309346143195985,\n",
    " 0.19381266389288723]\n",
    "Q3[0.12526170116128413,\n",
    " 0.22158712550112708,\n",
    " 0.2781322479219995,\n",
    " 0.09103437191167926,\n",
    " 0.28398455350391005]\n",
    "Q4[0.7296775045796745,\n",
    " 0.0960056126019086,\n",
    " 0.09261893561456087,\n",
    " 0.019943323950804608,\n",
    " 0.061754623253051366]\n",
    "24Q1[0.291033887076722,\n",
    " 0.24933095933660007,\n",
    " 0.27748689577019514,\n",
    " 0.05925214884598725,\n",
    " 0.12289610897049534]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([ 0.12492833,  0.24686267,  0.20019102,  0.21611675,  0.16855482,\n",
       "         0.25885825,  0.28643622,  0.112768  , -0.10713697]),\n",
       " array([151.72398003, 145.88720201, 137.26766132, 133.90208307,\n",
       "        128.15761098, 124.08582271, 117.37401577]))"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 重新计算权重和最终得分\n",
    "\n",
    "# 1. 数据准备\n",
    "data = np.array([[113,145,134.5,90,84,76,67,86,68],\n",
    "                 [114,132,122,82,90,77,67,85,65],\n",
    "                 [116,130,123.5,72,81,70,62,78,74],\n",
    "                 [110,120,118,69,71,63,70,82,52],\n",
    "                 [102,117,121.5,61,62,65,68,80,63],\n",
    "                 [103,111,120,67,71,58,58,77,65],\n",
    "                 [106,94,119.5,63,50,59,61,89,73]\n",
    "                 ])\n",
    "\n",
    "# 2. 数据标准化\n",
    "scaler = StandardScaler()\n",
    "data_scaled = scaler.fit_transform(data)\n",
    "\n",
    "# 3. 计算主成分\n",
    "pca = PCA()\n",
    "pca.fit(data_scaled)\n",
    "components = pca.components_\n",
    "explained_variance_ratio = pca.explained_variance_ratio_\n",
    "\n",
    "# 4. 计算载荷\n",
    "loadings = components\n",
    "\n",
    "# 5. 计算方差比例\n",
    "variance_ratio = explained_variance_ratio\n",
    "\n",
    "# 6. 计算标准差的倒数\n",
    "std_inverse = 1 / scaler.scale_\n",
    "\n",
    "# 7. 计算指标权重\n",
    "weights = np.sum(loadings * np.expand_dims(variance_ratio, axis=1) * std_inverse, axis=0)\n",
    "\n",
    "# 8. 对原始数据打分\n",
    "scores = data.dot(weights)\n",
    "\n",
    "# 输出权重和最终得分\n",
    "weights, scores\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "ai",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
